/*
 * @(#) $Headers$
 *
 * Copyright (C) 2007  Forklabs Daniel Léonard
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package ca.forklabs.media.jai.operator;

import java.awt.RenderingHints;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.ParameterBlock;
import java.awt.image.renderable.RenderableImage;
import java.util.Collection;
import javax.media.jai.JAI;
import javax.media.jai.OperationDescriptor;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.ParameterListDescriptor;
import javax.media.jai.registry.CollectionRegistryMode;
import javax.media.jai.registry.RenderableCollectionRegistryMode;
import ca.forklabs.media.jai.CollectionDescriptor;

/**
 * Class {@code ApplyToCollectionDescriptor} is an {@link OperationDescriptor}
 * describing the <em>applytocollection</em> operation. This operation applies
 * the same operation to all the image of a collection.
 * <p>
 * The <em>applytocollection</em> operation takes two parameters: the name of
 * the operation to apply and the parameter of the operation. No source need
 * to be added to the parameter, it will be done internally.
 *
 * <table border=1>
 * <caption>Resource List</caption>
 * <tr><th>Name</th>        <th>Value</th></tr>
 * <tr><td>GlobalName</td>  <td>ApplyToCollection</td></tr>
 * <tr><td>LocalName</td>   <td>ApplyToCollection</td></tr>
 * <tr><td>Vendor</td>      <td>ca.forklabs.media.jai.opimage</td></tr>
 * <tr><td>Description</td> <td>Applies the same operator to a collection of images</td></tr>
 * <tr><td>DocURL</td>      <td>n/a</td></tr>
 * <tr><td>Version</td>     <td>$Version$</td></tr>
 * <tr><td>Arg0Desct</td>   <td>The operation name</td></tr>
 * <tr><td>Arg1Desct</td>   <td>The parameter block</td></tr>
 * </table>
 *
 * <table border=1>
 * <caption>Parameter List</caption>
 * <tr><th>Name</th>         <th>Class Type</th>               <th>Default Value</th></tr>
 * <tr><td>operation</td>    <td>{@link String}</td>           <td>{@code "null"}</td>
 * <tr><td>parameters</td>   <td>{@link ParameterBlock}</td>   <td>{@code new ParameterBlock()}</td>
 * </table>
 *
 * @author   <a href="mailto:forklabs at gmail.com?subject=ca.forklabs.media.jai.operator.ApplyToCollectionDescriptor">Daniel Léonard</a>
 * @version $Revision$
 */
public class ApplyToCollectionDescriptor extends CollectionDescriptor {

//---------------------------
// Class variables
//---------------------------

   /** <em>serialVersionUID</em>. */
   private static final long serialVersionUID = -131508813948168907L;

   /** The name of this operator. */
   @SuppressWarnings("nls")
   public static final String NAME = "ApplyToCollection";

   /** The name of the operation parameter. */
   @SuppressWarnings("nls")
   public static final String OPERATION_PARAMETER_NAME = "operation";
   /** The name of the parameter block parameter. */
   @SuppressWarnings("nls")
   public static final String PARAMETERS_PARAMETER_NAME = "parameters";

   /** The index in the parameter block of the operation parameter. */
   public static final int OPERATION_PARAMETER_INDEX = 0;
   /** The index in the parameter block of the parameter block parameter. */
   public static final int PARAMETERS_PARAMETER_INDEX = 1;

   /**
    * The resource strings that provide the general documentation and specify
    * the parameter list for this operation.
    */
   @SuppressWarnings("nls")
   private static final String[][] RESOURCES =
   {
      { "GlobalName",  ApplyToCollectionDescriptor.NAME, },
      { "LocalName",   ApplyToCollectionDescriptor.NAME, },
      { "Vendor",      "ca.forklabs.media.jai.opimage", },
      { "Description", ApplyToCollectionDescriptor.getDescription(), },
      { "DocURL",      "n/a", },
      { "Version",     "$Version$", },
      { "arg0Desc",    ApplyToCollectionDescriptor.getArg0Description(), },
      { "arg1Desc",    ApplyToCollectionDescriptor.getArg1Description(), },
   };

   /** The supported modes. */
   private static final String[] SUPPORTED_MODES =
   {
      CollectionRegistryMode.MODE_NAME,
      RenderableCollectionRegistryMode.MODE_NAME,
   };

   /** The name of the source, use default. */
   private static final String[] SOURCE_NAMES = null;

   /** The type of source for each mode. */
   private static final Class<?>[][] SOURCE_CLASSES = new Class<?>[][]
   {
      { Collection.class, },
      { Collection.class, },
   };

   /** The parameter list descriptor for all modes. */
   private static final ParameterListDescriptor PARAMETER_LIST_DESCRIPTOR = new CollectionDescriptor.EmptyParameterListDescriptor() {

      @Override
      public int getNumParameters() {
         int num_parameters = 2;
         return num_parameters;
         }

      @Override
      public Class<?>[] getParamClasses() {
         Class<?>[] clazzes = new Class<?>[] {
            String.class,
            ParameterBlock.class,
            };
         return clazzes;
         }

      @Override
      public Object getParamDefaultValue(String name) {
         int index = -1;
         if (ApplyToCollectionDescriptor.OPERATION_PARAMETER_NAME.equals(name)) {
            index = ApplyToCollectionDescriptor.OPERATION_PARAMETER_INDEX;
            }
         else if (ApplyToCollectionDescriptor.PARAMETERS_PARAMETER_NAME.equals(name)) {
            index = ApplyToCollectionDescriptor.PARAMETERS_PARAMETER_INDEX;
            }
         else {
         // this call will throw an exception
            super.getParamDefaultValue(name);
            }

         Object[] values = this.getParamDefaults();
         Object value = values[index];
         return value;
         }

      @Override
      @SuppressWarnings("nls")
      public Object[] getParamDefaults() {
      // defaults would be the null operator
      // with its parameter block
         Object[] defaults = new Object[] {
            "null",
            new ParameterBlock(),
            };
         return defaults;
         }

      @Override
      public String[] getParamNames() {
         String[] names = new String[] {
            ApplyToCollectionDescriptor.OPERATION_PARAMETER_NAME,
            ApplyToCollectionDescriptor.PARAMETERS_PARAMETER_NAME,
            };
         return names;
         }

      @Override
      public boolean isParameterValueValid(String name, Object value) {
      // there is not much to do but check
      // that the value is not null
         boolean is_valid = (null != value);
         return is_valid;
         }

      };

   /** Description of the parameters. */
   private static final ParameterListDescriptor[] PARAMETER_LIST_DESCRIPTORS = new ParameterListDescriptor[]
   {
      ApplyToCollectionDescriptor.PARAMETER_LIST_DESCRIPTOR,
      ApplyToCollectionDescriptor.PARAMETER_LIST_DESCRIPTOR,
   };


//---------------------------
// Constructors
//---------------------------

   /**
    * Constructor.
    */
   public ApplyToCollectionDescriptor() {
      super(RESOURCES, SUPPORTED_MODES, SOURCE_NAMES, SOURCE_CLASSES, PARAMETER_LIST_DESCRIPTORS);
      }


//---------------------------
// Class methods
//---------------------------

   /**
    * Creates and fills a new parameter block.
    * @param   mode   the rendering mode.
    * @param   source   the source image.
    * @param   operation   the name of the operation.
    * @param   parameters   the parameter block for the operation.
    * @return   a new parameter block.
    */
   protected static ParameterBlockJAI createParameterBlock(String mode, Object source, String operation, ParameterBlock parameters) {
      String name = ApplyToCollectionDescriptor.NAME;
      ParameterBlockJAI pb = new ParameterBlockJAI(name, mode);
      if (null != source) {
         pb.addSource(source);
         }
      pb.setParameter(ApplyToCollectionDescriptor.OPERATION_PARAMETER_NAME, operation);
      pb.setParameter(ApplyToCollectionDescriptor.PARAMETERS_PARAMETER_NAME, parameters);
      return pb;
      }

   /**
    * Performs the operation on a collection of rendered images.
    * @param   sources   the source images.
    * @param   operation   the name of the operation.
    * @param   parameters   the parameter block for the operation.
    * @param   hints    the rendering hints, may be {@code null}.
    * @return   the rendered result image.
    */
   @SuppressWarnings("unchecked")
   public static Collection<RenderedImage> createCollection(Collection<RenderedImage> sources, String operation, ParameterBlock parameters, RenderingHints hints)  {
      String name = ApplyToCollectionDescriptor.NAME;
      String mode = CollectionRegistryMode.MODE_NAME;
      ParameterBlockJAI parameter_block = ApplyToCollectionDescriptor.createParameterBlock(mode, sources, operation, parameters);
      Collection<RenderedImage> sinks = JAI.createCollection(name, parameter_block, hints);
      return sinks;
      }

   /**
    * Performs the operation on a collection of renderable images.
    * @param   sources   the source images.
    * @param   operation   the name of the operation.
    * @param   parameters   the parameter block for the operation.
    * @param   hints    the rendering hints, may be {@code null}.
    * @return   the rendered result image.
    */
   @SuppressWarnings("unchecked")
   public static Collection<RenderableImage> createRenderableCollection(Collection<RenderableImage> sources, String operation, ParameterBlock parameters, RenderingHints hints)  {
      String name = ApplyToCollectionDescriptor.NAME;
      String mode = RenderableCollectionRegistryMode.MODE_NAME;
      ParameterBlockJAI parameter_block = ApplyToCollectionDescriptor.createParameterBlock(mode, sources, operation, parameters);
      Collection<RenderableImage> sinks = JAI.createRenderableCollection(name, parameter_block, hints);
      return sinks;
      }


//---------------------------
// External resources methods
//---------------------------

   /**
    * Gets the description of this operation.
    * @return   the description message.
    */
   protected static String getDescription() {
      String key = Resources.APPLY_TO_COLLECTION_DESCRIPTION;
      String message = Resources.getLocalizedString(key);
      return message;
      }

   /**
    * Gets the description for the first argument, the operation name.
    * @return   the description message.
    */
   protected static String getArg0Description() {
      String key = Resources.APPLY_TO_COLLECTION_ARG0_DESCRIPTION;
      String message = Resources.getLocalizedString(key);
      return message;
      }

   /**
    * Gets the description for the second argument, the parameter block.
    * @return   the description message.
    */
   protected static String getArg1Description() {
      String key = Resources.APPLY_TO_COLLECTION_ARG1_DESCRIPTION;
      String message = Resources.getLocalizedString(key);
      return message;
      }

   }
